<?php
declare(strict_types=1);

namespace lib\pay\helpers;

use lib\pay\Pay;
use lib\pay\PayException;
use OpenSSLAsymmetricKey;

class PaySign {
    /**
     * 开发模式
     */
    const IS_DEV_MODE                       = false; # true 测试模式

    # 小程序密钥配置
    public      const WEIAPP_ID               = 'wx30c338f325983400'; # 小程序ID
    protected   const WEIAPP_KEY              = 'B252754AA65F60C606CC08CB0CA6BFAE';

    # 公众号密钥配置
    public      const WOA_ID                  = 'wx777a20fb25288ef4'; # 公众号ID
    protected   const WOA_TOKEN               = '34kjhnsdo5iXfj89023rkZsdDyBx8Udg';
    protected   const WOA_KEY                 = 'f379b114f69c84bdcc56346deafa77ff';

#######################################################支付宝#######################################################
    # 支付宝密钥配置
    public const ALIPAY_ID                  = '2017022005774381'; # 设置支付宝APPID
    protected ?OpenSSLAsymmetricKey $alipayPrivateKey = null;
    protected ?OpenSSLAsymmetricKey $alipayPublicKey = null;
    # 签名私钥
    protected const ALIPAY_PRIV_KEY         = <<<EOF
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAtqbdQvbbLYTOs8WKpInXcMxIfEhlHB8uD5SmXuGoP/iY/0LC
WP6Wr8zG9u3dvldsRgbdOyQs7kjBWgaUGAUpzdSQfPlQkqryH8FUTTnnoCvpBgjW
yOzeSKUmWm719IPe9JblbMH5I/BUmTJ4vOrhYI/J5B+EN691G2B61N/0q2/HyAuc
HlZKFeVk6Ck0EoJJXoMNbkbTMGkmCxUbClh7R06Zy0dRtxtKcOyUl4vEUwMl8RJP
mvDvsE70IcT3nL2tVvRWdLw/VXBjWakVHEFpMKNYzM11/PouTvunY3rx/YN5IFDW
a0E6bKYCBDuQ5yNye+zXGXsFcAlJbfxpmKCYGQIDAQABAoIBAQCq6bePqsjrbiOx
ir6yOp3TWgTV7zRVvUNvpuyLSmMTAT/BVCnh9tDwThE8DNb6/nk9ibzIU5CLpJ7w
68j2NRaqGSbfGrhvlfCdEF4fKXj5oz0YvXqmZyeVGJyr8LrMA/3EJ9MlEtlb7M5s
0BK0zKD6p3IGugsRxGgzpvMpcStUotyWCZriCvMsWcD5U6oP/9a1UuSp+XoBWNuj
Ilue4FwR0KtRzP1a9DPHg38lZTbokNkgAEgkSjwqSvhgeFkNJgL2UNeIlJZiI+/r
cJJrDL1XP9iGc5/S7geJViX5KGiWSL4uoFkiXa7G5xu+/tXdPPpmj2+PswGp0rBH
Btgl3ZTRAoGBAO/UhoTcjeVH5RBabNZheAsryg6jMgQRqd8rBvoT8xvvZYmafZzJ
vSJMtaBe0otqTMale0Xw8aOpwF3kyBY0ovxdkS1ymij2yGcN6PB+5MxRl5HOH+xY
vV6xl2HHVzTV8mggeIJGRz/Mga+gv8SIyKb5qCX4ajq72r3GmQndCnmlAoGBAML3
cF1pG2o4z1IOljnvMsycHx++NfVtBf8ttXnx2Z2ALKKO9F13yXzsEzndaND9jWrv
McwzZyKhF2xsv8sLyzEpqW8bzkKB9m2NWbf0XZm6Wf7ZH6ZtLC6duQiPoIk5raje
n096gykBeXuRxZ/kss2H/xPoyXxqlZI/HhS+XRJlAoGABN35ROT89DQ7T9Ol9cvQ
ldlzpkxljXOWUPMclyKkgmKfWuWJuw7VCccowHJsL2we1sEw+UBkhv/A6abk8J5s
2FZFxfhXbJFli8Haglbw6byWKN1YBIHghfVwrwlOmcHlw3s1Nt+aPo816oyGl8R2
3fyfDvY1oa+CRuuq22pi9gkCgYBLW36H7F9XUDv5+H9iRy04XsO87jVG9mvR9OXn
C27UbL1T27NiCTHM4iaQQB8KYGZvxaJWzit3/BHkq6f6IEXaa8L8mh/AHyGTuIXM
D1y6VYgBdATCvAHOxtHFGFaxk6Sm1911x+G4UMSW2YIsSiY+QOl71YdDWqMTUuga
lnW87QKBgAWYuwdwUI4mbLSVnU9i6c41XQcb4gbVjKQ4Rp1qAgrkcQzAVA9lX4vE
k2hZt9H9D0Z3COUHPSbwCaEpjdIucZp6p6q6FgVMCB63lxMyqrWQ8SqoiiFoh1gW
uK5VUr1aDQEv4mFDhEO2sbGe69K+7EmstwYYleizFjDFXAPmvJIE
-----END RSA PRIVATE KEY-----
EOF;
    # 验签公钥
    protected const ALIPAY_PUB_KEY          = <<<EOF
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4Q+5O4DgjoqzaN6qCTAP
t4xYHq0+jrSievZ0FNdeuBEBn3BgYjMO4rrRD4q6dRynlXH54hbTy4XNcknGsDCs
6mKYbY1yTsqwL9wGso2mGIKdDWEjCqgoufOz+ms/29gYCpyYWYP9SNYYuyL+o1LD
etTEkHj9QYj250TTM+9SB1G+PHrhjuOY7NXoyUSJYqYlW+at5PbaMxWhGkSmFUjh
UKwkM+8hI89P2zyGmHV6+SlSnjexjd4HciZ9aeZ7iPpmUT9x+y2VOQrfb2iszlFX
cEvNXE8S6+OrovrzT7sLw0mUg/8Uc6uBLZRsrMA2vjdzR1RzGxv1LI11vZ7ZHqgd
UQIDAQAB
-----END PUBLIC KEY-----
EOF;


#######################################################嘉联支付#######################################################
# [嘉联支付][产品模式]我方用于签名的私钥
    const JLPAY_PRIVATE_STRING      = <<<EOF
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1Z9BFuX5C27so
EzaMlIKS+r80ov54zj/MzIonSGyKrdHnMgulAbuSiKZC3xSciM9rHF+46oFWm4+I
e33X97HOlDPc36fKsn6myFTWVbRBwOKGtzCH3Ce/Idr6PqjLRpblgteZ+kTJMRbL
49fEnOzra7rJQ3b/fB4I99ZAE42BvlahXvqJuH1/BE8Zqn5uSvDH1tKm6bV3oYAM
apK4OGBNMJoAFXBoCEMKV4BTnQmELq9qKYjm0VH7z1/HfBhm29R6skAs7FZDs3BI
niwOqEmYe9QQ8tkz7Vbi7lbWPJgptB/KkTYGlP4V9osIl14BqNBRBr6/k3NEXvRL
UHtumUD7AgMBAAECggEARzWPPi+IbrpOh3azTQ/nCcdAU2tANS/RP5VzDeSSJwYA
hZ7Rj15UwTq++TUUpDXYJhWnRbFYQCUkfNDtH1/t/keS7DsnZJwYt2OgWdqevcj3
oyY5+LrlJ1Qk32LFY7Y7+bAY7iqd4dRRPIwd4OIw5mENm3/OMJAKQj73bYO/YpQp
nxTDJq2AJ46Ovw+2rm1dcaqW6ZrRXgL8eeapAZlMtwBT73V7sY79+raGbkyFvXn0
YgllVbMrPsTpyQ+8dKjYfL4/yQ9oLYPdlw9GPEjcKdH7jrGxRDugSzter7+hvNQI
Lf7xZVROhFLdeJRR1B7Iv6T0fKT4dZY0J+Om8k9wcQKBgQDgRhjVG6p1G538IZ2u
7UUG3muYyIG3zlfBjPJm+sap/we3hd+OEt/JQVmD2Wt2jeU9x2Ot68cL5lRkp9Bv
Q+1nMoGFK1bp0hw0vmcKj4E2A8ZUeDayhSOKSJ03+T3B/WLni/kYGyBfSH+ByPYO
8aAk4ovwKRf8pcFzAsReHofCDQKBgQDPEUY+UCKz5MGDIrw/6Mq58AanvvvLLnL5
777VgHsusJW4OjsvvcGlfjH6mSvw/82YSSLiQP2lfrNwAjhkkel/6hYOdltllpaV
r9yGGx0zW5GZ8LCHWQWAB/XpCXkt+fKOOJevYY6nWq0XlWPd/qc9kWknDm/y8S6n
NzwFNjY1JwKBgQCV+8rXmezg7Fs3JnQBbAPhmBV004KMnZ3qfowNemAph7htb0YW
CWFHgkCPAHPxkOth6VosEaXHu31s4x1ti4vUm94qZNV3AWCDlWHrmhTbPqMAEnTh
5k/iRrV9nV1DwmTGXMF08Y8wqZc8AF0tmUFz6V2Ueqbj+yXn+E3Cc8BucQKBgBWg
i0Kk4gsCAIguz5SpPstO25MXqnrdPhsGxFrOUY9d2DVmt5nT6u7bEGNJLkK8pP+b
2+3ftd5cLmerg7JVXxsCGw2lpQQmR1IZDSJgoJslnD6E2hs43A80RaXyXFrF+WSL
WqRxvxGRsfR9oPGl0Ffo4R+4LU8li6bhaP5uXBkPAoGAF/tz4OX2RGyt/rBl95qd
Vo5XC8g0/exkn4exslDrTv/wAtPvleX14ae4n7DWOqBLI2tG1oAhmiRSj4EHBzEX
tojuKREofvzCkdvOG8zjkNuclUeMLTavE+WfMHHj+NABx4UPL47BeWfOwmVpZqKv
fqrWSdCu8leoWnqC/P2YWdo=
-----END PRIVATE KEY-----
EOF;
    # [嘉联支付][产品模式]嘉联支付提供的公钥 我方用于验签
    const JLPAY_PUBLIC_STRING       = <<<EOF
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApf2maNN0tXCDL7mqGd2d
+e7FEv33Hdw3LENlEgSF6PUHiE8Zk1sJhCqB/rN2s/wE+295tdoVxYqKWeROLlhr
3RWO4LXoKAUcHv3s72eWo8FxUm1rBQV0WqyMtOF9z9qFanL2kTQudEAoieJYhy8e
BHldFrhk1DnB0EeszcLLb9zvwE1lcxVL3eZJXokvvMxtOtFBO2wdrV1X1eOZiKoB
eHJvQ10ChnZRUeJez/KjWE1SXfME8Jje8Q0nH59wipktdODjFZEJCZLHqyf/t95n
evProoeLXD/jr6TMZekdLHt6vCvCafe2GkqNDEmor/X9gZXFVuG0Z9qIkuUXfhSS
VwIDAQAB
-----END PUBLIC KEY-----
EOF;
    protected static ?OpenSSLAsymmetricKey $jlPrivateKey = null;
    protected static ?OpenSSLAsymmetricKey $jlPublicKey = null;

#######################################################易宝支付#######################################################
# [易宝支付] 对方公钥 己方验签用
    protected const YEEPAY_PUB_KEY          = <<<EOF
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6p0XWjscY+gsyqKRhw9M
eLsEmhFdBRhT2emOck/F1Omw38ZWhJxh9kDfs5HzFJMrVozgU+SJFDONxs8UB0wM
ILKRmqfLcfClG9MyCNuJkkfm0HFQv1hRGdOvZPXj3Bckuwa7FrEXBRYUhK7vJ40a
fumspthmse6bs6mZxNn/mALZ2X07uznOrrc2rk41Y2HftduxZw6T4EmtWuN2x4CZ
8gwSyPAW5ZzZJLQ6tZDojBK4GZTAGhnn3bg5bBsBlw2+FLkCQBuDsJVsFPiGh/b6
K/+zGTvWyUcu+LUj2MejYQELDO3i2vQXVDk7lVi2/TcUYefvIcssnzsfCfjaorxs
uwIDAQAB
-----END PUBLIC KEY-----
EOF;

    # [易宝支付] 私钥 己方签名用
    protected CONST YEEPAY_PRIVATE_KEY     = <<<EOF
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDJuhG5pvNVXxV/
e890sLumb90tPI2OQOVfGLz8DP0QjEPE0KjldDPonOZPnG39dDln61dcTUyDPC/n
IjcjqG54LFElvD6o/AnxMYIOAsycKdgGW5yF59XE7fOnhbuZeuDfuCzWf2MhUcu+
YShwXRJ29RJmNG5e4SzUt4p9O/DShgZuDHaqKa9+Xuj14ndrOW/ONjZtpV6o3y2U
tYS6HUEbbJBYQWG83TiGqiGpV9Ibo/9fWhS+6Y+cCczSpbqKHnuW+rugm7zjiwGw
d3U9dExGeNHrVDvBRWNpvnU/sfsueqgVguVpMd8US1iC9TpD0WifcplPJBjkbGI0
ArRPq/PhAgMBAAECggEBAJvZLSiJWyVxuGItfTFh+Re1BOOWDKcCbDL0Ic15G2pV
c2Xy7wmWpSPpU+XdrPxLdq5am7ur3JjnPvsK7B6YWgBt/KNys9ZKIkQ9Q4UflIRx
r3v5+wtY+UaTr9KU90K0NFejKsDs2eE8GHSVC3ED9ugAnp5nk32p6cDNrCjkzkFV
+yrBF0CngvrGzzAYi34wztlVdco6l/u+zl/NCALFhs2bhlS1lMReckpVtTLXpALE
hT0ZVNor5f31UHPcAQWXhzs2SOP2vgZ0NRn+rCUP3BFahZFDJ5CB1PTk6ZVIg8mU
xd1/4XjGhnZT61mN5W61Ez7cO0NNzWQ3Dxq0GO3KZ6ECgYEA5VriV8+/vnSed5NO
O8+B6rQgmoh11DbZaicBJptXSZIUz05txBLm9/GccEfPE9O1QVBLii7Iu2Iw3iQn
2ME4YNl512kHVYMcIxFYgVkM5wi9wbgQTUdJsWdtpjuhBOj1TElaIsrAxMj1lwAx
wW2j88BxL3IGEjqHf2u8WXbvxgMCgYEA4SmC2tmccZKUqt5FyNyTK+bQZ9bday/a
wXQeYn1a2cp0FrUlzNuThhG3awmyDBeX+thWPzrRbWVaf2a2kQAmJp5KJMMMfGyY
zAY0pINOg4f2FVvKlMh8svx7SZrZN95qDvlPt7HGvIzPNwbxlrR4mbMzwu8m69YA
Sxc27PAY+0sCgYBbrRxUJUJriondGhBnb+ZqPl3Z5znR/aqh971KBUW6rp2Kz7qo
aTXRXc4+QzXOow0Mcl//d/vcir8lzCXxSiqS69r784tu7t1MVx6ddU7m+mN/D2fU
u+4E72awz5zpLYT/XUKeLZUoE3u3Q+iffIfQYtfbMySiHKsUj6fVyujEqQKBgBLV
kBaSYV22ryzjzt6QZNclRYWKGZdft2K7PddrOPBC2RcVLAZIz7xFOxx/AR+10Yaw
FfbQCril474Ib3kNlCNi1jzg++hkhRt74WdpfGXQN6tttDJh2tx19jIf+8+KkUCT
ZjGtczxOYv7tW8QJcJUawlep/Y14pymg1X1YUB6lAoGAKi1EFM7aVP6/fYgsb7ki
TGdlnDaPAxc2J3C++BtYlF+Qjxma88c7gfBIrSszbXYZWDn1A0bUpBrYBVcXAFDF
eaLPAc0S5Fg5CLanJibm9aptG+WFuf2e2uZ+dFyWAV/hsMYRXuJpSfBKo86OrKhv
xy6mGBJFQlC0q+oe54M86B8=
-----END PRIVATE KEY-----
EOF;

    # 己方私钥 签名数据用
    const MEMBERPAY_PRIVATE_STRING      = <<<EOF
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCxsCPHpATS8pzy
BALwFk+Dd1e7cjgWbEBTFpa7oNCq6UYI1W25vBc1QQGMsjdJ75uagtE3qw+IcY4X
QNX7zjtdUKgh8Yc5alQ+Ik9gmYGDTQ7pw0/6/ttby66P3PuiaidRBVHltE8EM8n/
s75CGEmKKFlRKq6IIAAsbmEaXYjgS+IDzNIKEFpnGrHCJ2m8m5/16SuaNhL1wU5y
yjIjppeFcM2u1gMjrLlQ6XVFNqgrolTrt9zrBD70YEWXhyGHVXBmBZ/0aCSPTwWs
NkEpP3tIiJErcBl8Jl0A6GzxFNd7/XnOkF5U6cJTEhsTz4tJ9NO4dptzKly25f4c
PEhMIg3LAgMBAAECggEAD19z2QPhvvZqia27K1Zizrb2iisZmycGcanUpKsHIqJI
At+kPJt/ToYvQiLxEZ5/UeDbhPtxvpZEetKLMNvo2uvtf/JLhrYiT7XcNDlTsS5r
ieHx+38tL0Xx9lRiGO0iNapGKZ9t7qkkYtEENuevBRr0j0coDnLmUPHDyOoqu2zw
Wbf71N2cXdtB2uDj3DPOloQVBMN42NQCm3HMGprOV97p+GkI5ETQ4547PAnbUu0R
saKWpaxZn16WuYBnt6NR06ae9btlXYjTq6nOqnAfwYXkFAF5+1Sz2vzBkjNTUKuL
tBmBaHE//uqR/V2nJyRGJdfkIzO17ysLSHQTdVFGMQKBgQDZPr73AQ11vq/JBOU6
OWw2JHpRmhipdT+blrMbz8nZF2C4NBdlFi7n7aubal1pmBe4xB4C3tEalSFG6egc
1Cw5IvvgPYGcfYZcC154DrQ+Le6TDRCXAySGepkBJm3UXwr0I3eTTtdOeVsm1sM1
N528GKGDEic7btTdtThSNaL+jQKBgQDRYuIUm67y8wWyMSt8q2I3ao0ffj3Y6xyt
vLzl6KKjZlSg7tMln8pXAwWOQwFdyOQRsXnfdC4d+TKemFmF059DDB2WV1jkUFpa
JG7uv2VN00fWe0/MTS5NX4tDvt94rwN7TMTtP+yv+40x02ndCLQ5Neiw77FbfDdN
kzN2hYgztwKBgHbRPpjR1o7DkFkdeFHz/h9OrCfdZAeqvPNX5PYdG4TEqH2W4ATF
sTngX69M6XJLYQ4JFXD0dOFZFy412GGMGfPWEnR+r1jrvoSxIyX+xM4NSSLcTmqJ
qXxzqSNb5U31/YOxskC7Kj8dWKFRbMq6dGbgAdYyI4r5/yqTZw5vj4oxAoGASlb1
NaPghVlLGGzkp6qhgFNQL3I+uxkeYYC1AFuMAr9+JHUmeiE1UZc9Dbk0bvu4HaAJ
SRCSnwmusygcAKuVy9QtXQc+BDGTIpX03McPTIZK5xd4yWxNmCLn6vGFne9lKQ2k
jSc4/XIuOxZ4a4V/lyBQsSEosvZzHBO7HcVjChkCgYEAgMTqPaU0JH3JfijvIWAe
YarxMX53xLkzibtozRTPRO2M/PEaV6GnkJ50NTUm8b8+cVxJwVWbhsxmufG1pbrz
z5qaMp08X+A1XUbIQkMicSm6lsMej0e3iNbQ7dW9ggsuQkfdDFoMTCPd7UH/8pgj
TyeofmUfHC/pvOfwyOT5+MA=
-----END PRIVATE KEY-----
EOF;

    # 计费端的公钥 验签用.
    const MEMBERPAY_PUBLIC_STRING      = <<<EOF
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKDKb793QvT+49I2ijdj
mOwbqG/uo2sa3PYk3zdAe4+mC/8lao9n0SrZCny4c8fWhKsot7nMgTgN6gsXosVq
Fpl0HKl/g2Wg8eVM4aQwCfwfTWbKiYgrVvB/YdDW+O2Cd15WfpkEX226KTBH9gjy
BytxP7GxSMPhoF2mbw7gdpb4xDldabmhwsKw4B0oMbO+FbYXqgn8+GyCKzskPp3L
3cQZh7G7lFBtbwLjznaEgUUpcyP6u/ImY+nOKIgdfEIFHZGlSFC66lLdCMMv91SO
iVp7LcAalutbMkOn5lPMj5JekVuloRYHKFFLgpXKNJbQlbZYS9o6RUNqhPY71hVM
BwIDAQAB
-----END PUBLIC KEY-----
EOF;

    protected static ?OpenSSLAsymmetricKey $memberPrivateKey = null;
    protected static ?OpenSSLAsymmetricKey $memberPublicKey = null;


    private static function jlLoadPrivateKey() :?OpenSSLAsymmetricKey{
        if(null === static::$jlPrivateKey)
            static::$jlPrivateKey = openssl_get_privatekey(static::JLPAY_PRIVATE_STRING);
        return static::$jlPrivateKey ?? null;
    }

    private static function jlLoadPublicKey() :?OpenSSLAsymmetricKey{
        if(null === static::$jlPublicKey)
            static::$jlPublicKey = openssl_get_publickey(static::JLPAY_PUBLIC_STRING);
        return static::$jlPublicKey ?? null;
    }

    private static function memberLoadPrivateKey() :?OpenSSLAsymmetricKey{
        if(null === static::$memberPrivateKey)
            static::$memberPrivateKey = openssl_get_privatekey(static::MEMBERPAY_PRIVATE_STRING);
        return static::$memberPrivateKey ?? null;
    }

    private static function memberLoadPublicKey() :?OpenSSLAsymmetricKey{
        if(null === static::$memberPublicKey)
            static::$memberPublicKey = openssl_get_publickey(static::MEMBERPAY_PUBLIC_STRING);
        return static::$memberPublicKey ?? null;
    }


    private static function alipayLoadSignKey() :?OpenSSLAsymmetricKey{
        if(null === static::$alipayPrivateKey)
            static::$alipayPrivateKey = openssl_get_privatekey(static::ALIPAY_PRIV_KEY);
        return static::$alipayPrivateKey ?? null;
    }

    private static function alipayLoadCheckKey() :?OpenSSLAsymmetricKey{
        if(null === static::$alipayPublicKey)
            static::$alipayPublicKey = openssl_get_privatekey(static::ALIPAY_PUB_KEY);
        return static::$alipayPublicKey ?? null;
    }

    private static function ToUrlParams(array $params)
    {
        $buff = "";
        foreach ($params as $k => $v) {
            if($k != "sign" && $v != "" && !is_array($v)){
                $buff .= $k . "=" . $v . "&";
            }
        }
        
        $buff = trim($buff, "&");
        return $buff;
    }

    private static function getSignContent(array $params){
        ksort($params);
        $stringToBeSigned = "";
        $i = 0;
        foreach ($params as $k => $v) {
            if(is_array($v)){ $v = static::getSignContent($v); }
            if (null!=$v && "@" != substr($v, 0, 1)) {
                if ($i == 0) {
                    $stringToBeSigned .= "$k" . "=" . "$v";
                } else {
                    $stringToBeSigned .= "&" . "$k" . "=" . "$v";
                }
                $i++;
            }
        }
        return $stringToBeSigned;
    }

    public static function sign(array $params, int $paySrc = Pay::SRC_JLPAY) : string {
        switch($paySrc){
        case Pay::SRC_JLPAY:
            ksort($params);
            $str = json_encode($params, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
            if(openssl_sign($str, $sign, static::jlLoadPrivateKey(), OPENSSL_ALGO_SHA256)){
                return base64_encode($sign);
            }
            throw new PayException('嘉联支付签名失败:' . $paySrc, 1012);
            break;
        case Pay::SRC_WXAPP:
            ksort($params);
            $string = static::ToUrlParams($params) . '&key='.static::WEIAPP_KEY;
            return strtoupper(md5($string));
        case Pay::SRC_WOA:
            ksort($params);
            $string = static::ToUrlParams($params) . '&key='.static::WOA_KEY;
            return strtoupper(md5($string));
        case Pay::SRC_ALIPAY:
            $string = static::getSignContent($params);
            if(openssl_sign($string, $sign, static::alipayLoadSignKey(), OPENSSL_ALGO_SHA256)){
                return base64_encode($sign);
            }
            throw new PayException('支付宝支付签名失败:' . $paySrc, 1012);
            break;
        case Pay::SRC_MEMBER:
            ksort($params);
            $str = json_encode($params, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
            if(openssl_sign($str, $sign, static::memberLoadPrivateKey(), OPENSSL_ALGO_SHA256)){
                return base64_encode($sign);
            }
            throw new PayException('会员支付签名失败:' . $paySrc, 1012);
            break;
        }
        throw new PayException('不支持的签名算法:' . $paySrc, 1012);
    }

    /**
     * 公钥验签
     */
    public static function verify(array $params, int $paySrc = Pay::SRC_JLPAY) : bool {
        switch($paySrc){
        case Pay::SRC_JLPAY: # 嘉联支付验签
            $sign = $params['sign'];
            unset($params['sign']);
            ksort($params);
            $str = json_encode($params, JSON_UNESCAPED_UNICODE |JSON_UNESCAPED_SLASHES);
            $result = (bool) openssl_verify($str, base64_decode($sign), static::jlLoadPublicKey(), OPENSSL_ALGO_SHA256);
            return $result;
        case Pay::SRC_ALIPAY:  # 支付宝验签
            $sign_type = $params['sign_type'] ?? 'RSA2';
            $sign = $params['sign'];
            
            $first_key = array_key_first($params);
            if(\preg_match('#^alipay_.*_response$#', $first_key)){
                $data_str = \json_encode($params[$first_key], JSON_UNESCAPED_UNICODE);
            }else{
                if(!empty($data['sign_type']))
                    unset($data['sign_type']);
                unset($data['sign']);
                $data_str = static::getSignContent($params);
            }
            if ("RSA2" == $sign_type) {
                $result = (bool)openssl_verify($data_str, base64_decode($sign), static::alipayLoadCheckKey(), OPENSSL_ALGO_SHA256);
            } else {
                $result = (bool)openssl_verify($data_str, base64_decode($sign), static::alipayLoadCheckKey());
            }
            return $result;
            break;
        case Pay::SRC_WOA:   # 公众号验签
            $sign = $params['sign'] ?? '';
            return static::sign($params, $paySrc) === $sign;
            break;
        case Pay::SRC_WXAPP: # 小程序验签
            $sign = $params['sign'] ?? '';
            return static::sign($params, $paySrc) === $sign;
            break;
        case Pay::SRC_MEMBER: # 会员支付验签
            $sign = $params['sign'];
            unset($params['sign']);
            ksort($params);
            $str = json_encode($params, JSON_UNESCAPED_UNICODE |JSON_UNESCAPED_SLASHES);
            $result = (bool) openssl_verify($str, base64_decode($sign), static::memberLoadPublicKey(), OPENSSL_ALGO_SHA256);
            return $result;
            break;
        }
        throw new PayException('不支持的签名算法:' . $paySrc, 1012);
    }
}